/*
	This script file is part of the Sonic 3 A.I.R. script software distribution.
	Copyright (C) 2017-2024 by Eukaryot

	Published under the GNU GPLv3 open source software license, see license.txt
	or https://www.gnu.org/licenses/gpl-3.0.en.html
*/



// Collectable Item

//# address-hook(0x036364) end(0x0363ca)
function void fn036364()
{
	objA0.mapping_offset = 0x036aa6
	objA0.sprite_attributes = 0x03c6
	objA0.render_flags |= render_flag.WORLD
	objA0.sprite_priority = 0x0280
	objA0.box_size.x = 0x08
	objA0.box_size.y = 0x08
	objA0.hitbox_extends.x = 0x04
	objA0.hitbox_extends.y = 0x08
	u16[A0 + 0x30] = objA0.position.x.u16
	objA0.value32 = objA0.position.y.u16
	objA0.value26 = objA0.subtype2c

	u8[A0 + 0x27] = (objA0.flags2a & 0x01) ? -1 : 1
	objA0.flags2a &= ~0x01
	objA0.state = 0x07
	objA0.collision_attributes = (collision.flag.SPECIAL | collision.size.6x6)

	objA0.update_address = 0x0363d0
	fn0363d0()
}


//# address-hook(0x0363d0) end(0x036436)
function void fn0363d0()
{
	fn03643c()

	D0.u8 = objA0.value26
	LookupSinCos()
	D1.s16 = u16[A0 + 0x30] + ((D1.s16 * 7) >> 5)
	D1.u16 &= level.width.bitmask
	D1.u16 += 0x0400
	objA0.position.x.u16 = D1.u16

	D0.u16 = objA0.value32 + ((D0.s16 * 7) >> 5)
	if (level.vertical_wrap == 0xff00)
	{
		D0.u16 &= level.height.bitmask
	}
	objA0.position.y.u16 = D0.u16

	objA0.value26 += u8[A0 + 0x27]

	Object.animationUpdate(0x036a58)
	AddAsDynamicObject()
	DrawObject()
}


//# address-hook(0x03643c) end(0x036462)
function void fn03643c()
{
	if (u8[A0 + 0x29] != 0)
	{
		A2 = 0xffffb000
		if (u8[A0 + 0x29] & 0x01)
		{
			u8[A0 + 0x29] &= ~0x01	// Needed for verification
			fn036464()
		}

		A2 = 0xffffb04a
		if (u8[A0 + 0x29] & 0x02)
		{
			u8[A0 + 0x29] &= ~0x02	// Needed for verification
			fn036464()
		}

		u8[A0 + 0x29] = 0
	}
}


//# address-hook(0x036464) end(0x036474)
function void fn036464()
{
	// Called when a character collects this item

	// Targets:
	//  - 0x036486	-> objA0.state = 0x00	-> Speed shoes
	//  - 0x0364d8	-> objA0.state = 0x01	-> Slow shoes
	//  - 0x03652a	-> objA0.state = 0x02	-> Switch
	//  - 0x0365e8	-> objA0.state = 0x03	-> Ring
	//  - 0x036612	-> objA0.state = 0x04	-> Bomb
	//  - 0x036652	-> objA0.state = 0x05	-> Banana
	//  - 0x036676	-> objA0.state = 0x06	-> Spring
	//  - 0x03669a	-> objA0.state = 0x07	-> That one's just empty...
	call tableLookupAddress(0x036476, objA0.state * 2)
}


//# address-hook(0x036486) end(0x0364d6)
function void fn036486()
{
	// Speed shoes
	u8[A2 + 0x2b] |= char.bonus.SPEED_UP
	u8[A2 + 0x36] = 0x4b
	if (A2 == 0xffffb000)
	{
		global.move.speedcap = 0x0c00
		global.move.acceleration = 0x18
		global.move.deceleration = 0x80
	}
	else
	{
		global.move.speedcap.tails = 0x0c00
		global.move.acceleration.tails = 0x18
		global.move.deceleration.tails = 0x80
	}
	objA0.state = 0x07
	u8[A0 + 0x28] = 0

	D1 = 0x036a1a
	D2 = 0x09
	fn036a38()
}


//# address-hook(0x0364d8) end(0x036528)
function void fn0364d8()
{
	// Slow shoes
	u8[A2 + 0x2b] |= char.bonus.SPEED_UP
	u8[A2 + 0x36] = 0x4b
	if (A2 == 0xffffb000)
	{
		global.move.speedcap = 0x0300
		global.move.acceleration = 0x08
		global.move.deceleration = 0x20
	}
	else
	{
		global.move.speedcap.tails = 0x0300
		global.move.acceleration.tails = 0x08
		global.move.deceleration.tails = 0x20
	}
	objA0.state = 0x07
	u8[A0 + 0x28] = 0

	D1 = 0x036a1a
	D2 = 0x09
	fn036a38()
}


//# address-hook(0x03652a) end(0x0365e6)
function void fn03652a()
{
	// Switch
	A2 = 0xffffb000
	A3 = 0xffffb04a
	D0.u8 = u8[A2 + 0x2b]
	u8[A2 + 0x2b] = u8[A3 + 0x2b]
	u8[A3 + 0x2b] = D0.u8
	D0.u8 = u8[A2 + 0x36]
	u8[A2 + 0x36] = u8[A3 + 0x36]
	u8[A3 + 0x36] = D0.u8

	D0.u16 = global.move.speedcap
	D1.u16 = global.move.acceleration
	D2.u16 = global.move.deceleration
	D3.u16 = global.move.speedcap.tails
	D4.u16 = global.move.acceleration.tails
	D5.u16 = global.move.deceleration.tails
	u16 backupD0 = D0.u16

	A1 = 0x1e3c00 + u8[A2 + 0x38] * 8
	global.move.speedcap = u16[(A1+=2)-2]
	global.move.acceleration = u16[(A1+=2)-2]
	global.move.deceleration = u16[(A1+=2)-2]

	A1 = 0x1e3c00 + u8[A3 + 0x38] * 8
	global.move.speedcap.tails = u16[(A1+=2)-2]
	global.move.acceleration.tails = u16[(A1+=2)-2]
	global.move.deceleration.tails = u16[(A1+=2)-2]

	D0.u16 = backupD0
	if (u8[A2 + 0x2b] & char.bonus.SPEED_UP)
	{
		global.move.speedcap = D3.u16
		global.move.acceleration = D4.u16
		global.move.deceleration = D5.u16
	}
	if (u8[A3 + 0x2b] & char.bonus.SPEED_UP)
	{
		global.move.speedcap.tails = D0.u16
		global.move.acceleration.tails = D1.u16
		global.move.deceleration.tails = D2.u16
	}
	objA0.state = 0x07
	u8[A0 + 0x28] = 0

	D1 = 0x036a1a
	D2 = 0x09
	fn036a38()
}


//# address-hook(0x0365e8) end(0x03660c)
function void fn0365e8()
{
	// Ring
	objA0.state = 0x07
	u8[A0 + 0x28] = 0

	D1 = 0x036a1a
	D2 = 0x08
	fn036a38()

	if (A2 == 0xffffb000)
	{
		CollectRing()
	}
	else
	{
		CollectRing_P2()
	}
}


//# address-hook(0x036612) end(0x036650)
function void fn036612()
{
	objA0.state = 0x07
	u8[A0 + 0x28] = 0
	u8[A0 + 0x29] = 0

	copyMemory(0xffffcb2c, A0, 0x2e)

	A1 = 0xffffcb2c
	objA1.update_address = 0x03669c
	u8[A1 + 0x20] = 0x04
	u16[A1 + 0x46] = u16[A2 + 0x46]
	if (u16[A2 + 0x0a] & sprite_attribute.PRIORITY)
	{
		objA1.sprite_attributes |= sprite_attribute.PRIORITY
	}
}


//# address-hook(0x036652) end(0x036674)
function void fn036652()
{
	objA0.state = 0x07
	u8[A0 + 0x28] = 0
	u8[A0 + 0x29] = 0

	D1 = 0x0366b6
	D2 = 0x05
	fn036a38()
	if (_equal())
	{
		u16[A1 + 0x46] = u16[A2 + 0x46]
	}
}


//# address-hook(0x036676) end(0x036698)
function void fn036676()
{
	objA0.state = 0x07
	u8[A0 + 0x28] = 0
	u8[A0 + 0x29] = 0

	D1 = 0x0366be
	D2 = 0x06
	fn036a38()
	if (_equal())
	{
		u16[A1 + 0x46] = u16[A2 + 0x46]
	}
}


//# address-hook(0x03669a) end(0x03669a)
function void fn03669a()
{
}


//# address-hook(0x03669c) end(0x0366b4)
function void fn03669c()
{
	objA0.groundspeed = -0x400
	objA0.value26 = 0
	objA0.flags2a = 0
	D2 = 0x0368aa
	fn0366c4()
}


//# address-hook(0x0366b6) end(0x0366bc)
function void fn0366b6()
{
	D2 = 0x0367c2
	fn0366c4()
}


//# address-hook(0x0366be) end(0x0366be)
function void fn0366be()
{
	D2 = 0x03670c
	fn0366c4()
}


//# address-hook(0x0366c4) end(0x036708)
function void fn0366c4()
{
	u32 backupD2 = D2
	UpdateMovementSimple()
	CheckGroundCollision()
	D2 = backupD2
	if (D1.s16 < 0)
	{
		objA0.position.y.u16 += D1.u16
		u32[A0] = D2
		objA0.collision_attributes = (collision.flag.SPECIAL | collision.size.6x6)
	}
	if (level.vertical_wrap == 0xff00)
	{
		objA0.position.y.u16 &= level.height.bitmask
	}

	D0.u16 = move_area.bottom.current + 0x60
	if (D0.s16 < s16[A0 + 0x14])
	{
		UnloadObject()
	}
	else
	{
		fn036a1a()
	}
}



// Competition mode spring item

//# address-hook(0x03670c) end(0x036758)
function void fn03670c()
{
	if (u8[A0 + 0x29] != 0)
	{
		A2 = 0xffffb000
		if (u8[A0 + 0x29] & 0x01)
		{
			u8[A0 + 0x29] &= ~0x01
			fn03675e()
		}
		A2 = 0xffffb04a
		if (u8[A0 + 0x29] & 0x02)
		{
			u8[A0 + 0x29] &= ~0x02
			fn03675e()
		}
		u8[A0 + 0x29] = 0
	}

	Object.animationUpdate(0x036a58)
	if (objA0.base_state == 0)
	{
		if (objA0.state != 0x09)
		{
			AddAsDynamicObject()
		}
		DrawObject()
	}
	else
	{
		UnloadObject()
	}
}


//# address-hook(0x03675e) end(0x0367bc)
function void fn03675e()
{
	D0.u16 = u16[A2 + 0x46]
	if (D0.u16 != u16[A0 + 0x46])
		return

	objA0.state = 0x0a
	u16[A2 + 0x1a] = 0xf600
	u8[A2 + 0x2a] |= 0x02
	u8[A2 + 0x2a] &= ~0x10
	u8[A2 + 0x2a] &= ~0x20
	u8[A2 + 0x40] = 0
	u16[A2 + 0x1c] = 0x01
	u8[A2 + 0x27] = 0x01
	u8[A2 + 0x20] = 0
	u8[A2 + 0x30] = 0
	u8[A2 + 0x31] = 0x04
	if (u8[A2 + 0x2a] & 0x01)
	{
		s8[A2 + 0x27] = -s8[A2 + 0x27]
		s16[A2 + 0x1c] = -s16[A2 + 0x1c]
	}
	playSound(0x7b)
}



// Competition mode banana item

//# address-hook(0x0367c2) end(0x036846)
function void fn0367c2()
{
	if (u8[A0 + 0x29] != 0)
	{
		A2 = 0xffffb000
		if (u8[A0 + 0x29] & 0x01)
		{
			u8[A0 + 0x29] &= ~0x01
			fn03684c()
		}
		A2 = 0xffffb04a
		if (u8[A0 + 0x29] & 0x02)
		{
			u8[A0 + 0x29] &= ~0x02
			fn03684c()
		}
		u8[A0 + 0x29] = 0
	}

	Object.animationUpdate(0x036a58)
	if (u8[A0 + 0x3c] != 0)
	{
		A1 = 0xffff0000 + objA0.value3e
		--u8[A0 + 0x3c]
		if (u8[A0 + 0x3c] != 0)
		{
			bool carry = false
			D1.u16 = 0x20
			D0.u16 = u16[A1 + 0x1c]
			if (D0.s16 < 0)
			{
				carry = (u32(u16[A1 + 0x1c]) + D1.u16 >= 0x10000)
				u16[A1 + 0x1c] += D1.u16
			}
			else
			{
				carry = (u16[A1 + 0x1c] < D1.u16)
				u16[A1 + 0x1c] -= D1.u16
			}
			if (!carry)
			{
				AddAsDynamicObject()
				DrawObject()
				return
			}
			u16[A1 + 0x1c] = 0
		}
		u16[A1 + 0x32] = 0x05
		u8[A1 + 0x2b] &= 0x7f
	}

	if (objA0.base_state == 0)
	{
		AddAsDynamicObject()
		DrawObject()
	}
	else
	{
		UnloadObject()
	}
}


//# address-hook(0x03684c) end(0x0368a8)
function void fn03684c()
{
	if (u16[A2 + 0x46] == u16[A0 + 0x46] && s8[A2 + 0x2b] >= 0)
	{
		if ((u8[A2 + 0x2a] & 0x02) == 0 && u16[A2 + 0x1c] != 0)
		{
			objA0.state = 0x09
			objA0.collision_attributes = 0

			D1.s16 = (s16[A2 + 0x1c] < 0) ? -0x0200 : 0x0200
			if (abs(s16[A2 + 0x1c]) < 0x0200)
			{
				s16[A2 + 0x1c] += D1.s16
			}
			s16[A2 + 0x1c] <<= 1
			u8[A2 + 0x20] = 0x1b
			u8[A2 + 0x2b] |= 0x80

			objA0.value3e = A2.u16
			u8[A0 + 0x3c] = 0x3c
		}
	}
}



// Competition mode bomb item

//# address-hook(0x0368aa) end(0x036900)
function void fn0368aa()
{
	if (u8[A0 + 0x29] != 0)
	{
		A2 = 0xffffb000
		if (u8[A0 + 0x29] & 0x01)
		{
			u8[A0 + 0x29] &= ~0x01
			call 0x036906
		}
		A2 = 0xffffb04a
		if (u8[A0 + 0x29] & 0x02)
		{
			u8[A0 + 0x29] &= ~0x02
			call 0x036906
		}
		u8[A0 + 0x29] = 0
	}

	fn036926()
	objA0.animation.sprite = 0x11 + ((objA0.value26 + 0x10) >> 5)

	if (move_area.bottom.current + 0x60 >= s16[A0 + 0x14])
	{
		AddAsDynamicObject()
		DrawObject()
	}
	else
	{
		UnloadObject()
	}
}


//# address-hook(0x036906) end(0x036920)
function void fn036906()
{
	D0.u16 = u16[A2 + 0x46]
	if (D0.u16 != u16[A0 + 0x46])
		return

	u32[A0] = 0x036a1a
	objA0.state = 0x0b
	A1 = A2
	DamageCharacter()
}


//# address-hook(0x036926) end(0x036a18)
function void fn036926()
{
	if ((objA0.flags2a & 0x02) == 0)
	{
		D0.u8 = objA0.value26
		LookupSinCos()

		D1.s32 = s32(D1.s16) * objA0.groundspeed
		D1.s32 >>= 8
		objA0.compound.sprite1.position.x = D1.u16

		D0.s32 = s32(D0.s16) * objA0.groundspeed
		D0.s32 >>= 8
		objA0.compound.sprite1.position.y = D0.u16

		UpdateMovementStraightSimple()

		objA0.position.y.u16 &= level.height.bitmask
		objA0.position.x.u16 &= level.width.bitmask
		objA0.position.x.u16 += 0x0400
		Character.UpdateRotationOnGround_partial()

		D0.u8 = objA0.value26
		if (D0.u8 == 0)
		{
			fn00fdec()
			if (D1.s16 < 0)
			{
				objA0.position.x.u16 -= D1.u16
				u32[A0] = 0x036a1a
				objA0.state = 0x0b
			}
		}
	}
	else
	{
		objA0.compound.sprite1.position.x -= 0x10
		if (objA0.velocity.x <= -0x0400)
		{
			objA0.compound.sprite1.position.x = 0xfc00
		}
		UpdateMovementSimple()
		D0.u16 = level.height.bitmask
		objA0.position.y.u16 &= D0.u16
		D0.u16 = level.width.bitmask
		objA0.position.x.u16 &= D0.u16
		objA0.position.x.u16 += 0x0400

		fn00f894()
		if (D1.s16 < 0)
		{
			objA0.position.y.u16 += D1.u16
			objA0.flags2a &= ~0x02
			objA0.value26 = 0
			return
		}

		D0.s8 = objA0.value26
		if (D0.s8 != 0)
		{
			if (D0.s8 < 0)
				D0.s8 = min(D0.s8 + 2, 0)
			else
				D0.s8 = max(D0.s8 - 2, 0)
			objA0.value26 = D0.s8
		}
		if (D0.s8 == 0)
		{
			fn00fdec()
			if (D1.s16 < 0)
			{
				objA0.position.x.u16 -= D1.u16
				u32[A0] = 0x036a1a
				objA0.state = 0x0b
			}
		}
	}
}



// Shared code

//# address-hook(0x036a1a) end(0x036a32)
function void fn036a1a()
{
	Object.animationUpdate(0x036a58)
	if (objA0.base_state == 0)
	{
		DrawObject()
	}
	else
	{
		UnloadObject()
	}
}


//# address-hook(0x036a38) end(0x036a56)
function void fn036a38()
{
	if (allocDynamicObjectAfterA0())
	{
		copyMemory(A1, A0, 0x2e)

		u32[A1] = D1
		u8[A1 + 0x20] = D2.u8
		D0 = 0
	}
}
